// META: title=test WebNN API tanh operation
// META: global=window,dedicatedworker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
// META: script=../resources/utils.js
// META: timeout=long

'use strict';

// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-tanh-method
// Compute the hyperbolic tangent function of the input tensor. The calculation
// follows the expression (exp(2 * x) - 1) / (exp(2 * x) + 1).
//
// MLOperand tanh(MLOperand input);


const getTanhPrecisionTolerance = (graphResources) => {
  const toleranceValueDict = {float32: 1 / 1024, float16: 1 / 512};
  const expectedDataType =
      getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs);
  return {metricType: 'ATOL', value: toleranceValueDict[expectedDataType]};
};

const tanhTests = [
  {
    'name': 'tanh float32 1D constant tensor',
    'graph': {
      'inputs': {
        'tanhInput': {
          'data': [
            5.473527431488037,   -1.1535595655441284,  0.4074455797672272,
            1.8297704458236694,  2.869000196456909,    -4.570195198059082,
            4.146744251251221,   -4.065934181213379,   -3.7128469944000244,
            0.9077175259590149,  -0.11083049327135086, 5.955096244812012,
            1.7831857204437256,  4.023128509521484,    5.587857723236084,
            -5.280653953552246,  1.4147950410842896,   -5.707716941833496,
            -1.443918228149414,  -1.9129083156585693,  2.7495968341827393,
            -0.7420240044593811, 4.856568336486816,    -0.7563357949256897
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'},
          'constant': true
        }
      },
      'operators': [{
        'name': 'tanh',
        'arguments': [{'input': 'tanhInput'}],
        'outputs': 'tanhOutput'
      }],
      'expectedOutputs': {
        'tanhOutput': {
          'data': [
            0.9999647736549377,  -0.8189298510551453, 0.38630160689353943,
            0.9498035907745361,  0.9935782551765442,  -0.9997855424880981,
            0.9994998574256897,  -0.9994121193885803, -0.9988092184066772,
            0.7200349569320679,  -0.1103789210319519, 0.9999865293502808,
            0.945036768913269,   0.9993596076965332,  0.9999719858169556,
            -0.9999482035636902, 0.8885080814361572,  -0.9999779462814331,
            -0.894483745098114,  -0.9573289752006531, 0.9918531775474548,
            -0.6303664445877075, 0.9998790621757507,  -0.6389135718345642
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'tanh float32 1D tensor',
    'graph': {
      'inputs': {
        'tanhInput': {
          'data': [
            5.473527431488037,   -1.1535595655441284,  0.4074455797672272,
            1.8297704458236694,  2.869000196456909,    -4.570195198059082,
            4.146744251251221,   -4.065934181213379,   -3.7128469944000244,
            0.9077175259590149,  -0.11083049327135086, 5.955096244812012,
            1.7831857204437256,  4.023128509521484,    5.587857723236084,
            -5.280653953552246,  1.4147950410842896,   -5.707716941833496,
            -1.443918228149414,  -1.9129083156585693,  2.7495968341827393,
            -0.7420240044593811, 4.856568336486816,    -0.7563357949256897
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'tanh',
        'arguments': [{'input': 'tanhInput'}],
        'outputs': 'tanhOutput'
      }],
      'expectedOutputs': {
        'tanhOutput': {
          'data': [
            0.9999647736549377,  -0.8189298510551453, 0.38630160689353943,
            0.9498035907745361,  0.9935782551765442,  -0.9997855424880981,
            0.9994998574256897,  -0.9994121193885803, -0.9988092184066772,
            0.7200349569320679,  -0.1103789210319519, 0.9999865293502808,
            0.945036768913269,   0.9993596076965332,  0.9999719858169556,
            -0.9999482035636902, 0.8885080814361572,  -0.9999779462814331,
            -0.894483745098114,  -0.9573289752006531, 0.9918531775474548,
            -0.6303664445877075, 0.9998790621757507,  -0.6389135718345642
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'tanh float32 2D tensor',
    'graph': {
      'inputs': {
        'tanhInput': {
          'data': [
            5.473527431488037,   -1.1535595655441284,  0.4074455797672272,
            1.8297704458236694,  2.869000196456909,    -4.570195198059082,
            4.146744251251221,   -4.065934181213379,   -3.7128469944000244,
            0.9077175259590149,  -0.11083049327135086, 5.955096244812012,
            1.7831857204437256,  4.023128509521484,    5.587857723236084,
            -5.280653953552246,  1.4147950410842896,   -5.707716941833496,
            -1.443918228149414,  -1.9129083156585693,  2.7495968341827393,
            -0.7420240044593811, 4.856568336486816,    -0.7563357949256897
          ],
          'descriptor': {'dimensions': [4, 6], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'tanh',
        'arguments': [{'input': 'tanhInput'}],
        'outputs': 'tanhOutput'
      }],
      'expectedOutputs': {
        'tanhOutput': {
          'data': [
            0.9999647736549377,  -0.8189298510551453, 0.38630160689353943,
            0.9498035907745361,  0.9935782551765442,  -0.9997855424880981,
            0.9994998574256897,  -0.9994121193885803, -0.9988092184066772,
            0.7200349569320679,  -0.1103789210319519, 0.9999865293502808,
            0.945036768913269,   0.9993596076965332,  0.9999719858169556,
            -0.9999482035636902, 0.8885080814361572,  -0.9999779462814331,
            -0.894483745098114,  -0.9573289752006531, 0.9918531775474548,
            -0.6303664445877075, 0.9998790621757507,  -0.6389135718345642
          ],
          'descriptor': {'dimensions': [4, 6], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'tanh float32 3D tensor',
    'graph': {
      'inputs': {
        'tanhInput': {
          'data': [
            5.473527431488037,   -1.1535595655441284,  0.4074455797672272,
            1.8297704458236694,  2.869000196456909,    -4.570195198059082,
            4.146744251251221,   -4.065934181213379,   -3.7128469944000244,
            0.9077175259590149,  -0.11083049327135086, 5.955096244812012,
            1.7831857204437256,  4.023128509521484,    5.587857723236084,
            -5.280653953552246,  1.4147950410842896,   -5.707716941833496,
            -1.443918228149414,  -1.9129083156585693,  2.7495968341827393,
            -0.7420240044593811, 4.856568336486816,    -0.7563357949256897
          ],
          'descriptor': {'dimensions': [2, 3, 4], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'tanh',
        'arguments': [{'input': 'tanhInput'}],
        'outputs': 'tanhOutput'
      }],
      'expectedOutputs': {
        'tanhOutput': {
          'data': [
            0.9999647736549377,  -0.8189298510551453, 0.38630160689353943,
            0.9498035907745361,  0.9935782551765442,  -0.9997855424880981,
            0.9994998574256897,  -0.9994121193885803, -0.9988092184066772,
            0.7200349569320679,  -0.1103789210319519, 0.9999865293502808,
            0.945036768913269,   0.9993596076965332,  0.9999719858169556,
            -0.9999482035636902, 0.8885080814361572,  -0.9999779462814331,
            -0.894483745098114,  -0.9573289752006531, 0.9918531775474548,
            -0.6303664445877075, 0.9998790621757507,  -0.6389135718345642
          ],
          'descriptor': {'dimensions': [2, 3, 4], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'tanh float32 4D tensor',
    'graph': {
      'inputs': {
        'tanhInput': {
          'data': [
            5.473527431488037,   -1.1535595655441284,  0.4074455797672272,
            1.8297704458236694,  2.869000196456909,    -4.570195198059082,
            4.146744251251221,   -4.065934181213379,   -3.7128469944000244,
            0.9077175259590149,  -0.11083049327135086, 5.955096244812012,
            1.7831857204437256,  4.023128509521484,    5.587857723236084,
            -5.280653953552246,  1.4147950410842896,   -5.707716941833496,
            -1.443918228149414,  -1.9129083156585693,  2.7495968341827393,
            -0.7420240044593811, 4.856568336486816,    -0.7563357949256897
          ],
          'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'tanh',
        'arguments': [{'input': 'tanhInput'}],
        'outputs': 'tanhOutput'
      }],
      'expectedOutputs': {
        'tanhOutput': {
          'data': [
            0.9999647736549377,  -0.8189298510551453, 0.38630160689353943,
            0.9498035907745361,  0.9935782551765442,  -0.9997855424880981,
            0.9994998574256897,  -0.9994121193885803, -0.9988092184066772,
            0.7200349569320679,  -0.1103789210319519, 0.9999865293502808,
            0.945036768913269,   0.9993596076965332,  0.9999719858169556,
            -0.9999482035636902, 0.8885080814361572,  -0.9999779462814331,
            -0.894483745098114,  -0.9573289752006531, 0.9918531775474548,
            -0.6303664445877075, 0.9998790621757507,  -0.6389135718345642
          ],
          'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'tanh float32 5D tensor',
    'graph': {
      'inputs': {
        'tanhInput': {
          'data': [
            5.473527431488037,   -1.1535595655441284,  0.4074455797672272,
            1.8297704458236694,  2.869000196456909,    -4.570195198059082,
            4.146744251251221,   -4.065934181213379,   -3.7128469944000244,
            0.9077175259590149,  -0.11083049327135086, 5.955096244812012,
            1.7831857204437256,  4.023128509521484,    5.587857723236084,
            -5.280653953552246,  1.4147950410842896,   -5.707716941833496,
            -1.443918228149414,  -1.9129083156585693,  2.7495968341827393,
            -0.7420240044593811, 4.856568336486816,    -0.7563357949256897
          ],
          'descriptor': {'dimensions': [2, 1, 4, 1, 3], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'tanh',
        'arguments': [{'input': 'tanhInput'}],
        'outputs': 'tanhOutput'
      }],
      'expectedOutputs': {
        'tanhOutput': {
          'data': [
            0.9999647736549377,  -0.8189298510551453, 0.38630160689353943,
            0.9498035907745361,  0.9935782551765442,  -0.9997855424880981,
            0.9994998574256897,  -0.9994121193885803, -0.9988092184066772,
            0.7200349569320679,  -0.1103789210319519, 0.9999865293502808,
            0.945036768913269,   0.9993596076965332,  0.9999719858169556,
            -0.9999482035636902, 0.8885080814361572,  -0.9999779462814331,
            -0.894483745098114,  -0.9573289752006531, 0.9918531775474548,
            -0.6303664445877075, 0.9998790621757507,  -0.6389135718345642
          ],
          'descriptor': {'dimensions': [2, 1, 4, 1, 3], 'dataType': 'float32'}
        }
      }
    }
  }
];

if (navigator.ml) {
  tanhTests.forEach((test) => {
    webnn_conformance_test(
        buildGraphAndCompute, getTanhPrecisionTolerance, test);
  });
} else {
  test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
}
